import type { HttpError, HttpRequestConfig, HttpResponse, HttpTask } from '../../luch-request'
import useUi from '../../../manager/useUi'
import { toast } from '../../platform'

const ui = useUi()
let reqTimes = 0
let timer: NodeJS.Timeout | null = null

interface LoadingConfig {
  /** @description 是否使用系统toast作为loading */
  useSystemLoading?: boolean
  /** @description 最大显示loading时间，单位ms */
  duration?: number
  /** @description 低于指定毫秒时，不显示loading，默认为100ms，即超过指定时间才显示loading */
  maskTime?: number
  /** @description loading标题 */
  title?: string
  /** 是否显示loading遮罩层 */
  mask?: boolean
  /** @description loading图标 */
  icon?: string

  showBusiTip?: boolean
  showTip?: boolean
  msgKey?: string
}
function resetTime() {
  timer && clearTimeout(timer)
  timer = null
}
function __showLoading({ useSystemLoading, title, icon, mask, duration, maskTime }: LoadingConfig) {
  if (useSystemLoading) {
    uni.showToast({
      title,
      image: icon,
      duration,
      mask
    })
  }
  else {
    ui.showRequestLoading({ title, icon, mask, duration, maskTime })
  }
}
function __hideLoading(useSystemLoading: boolean) {
  if (useSystemLoading) {
    uni.hideToast()
  }
  else {
    ui.hideRequestLoading()
  }
}

function showLoading({ useSystemLoading, duration, maskTime = 100, mask = true, title = '正在加载中...', icon }: LoadingConfig) {
  if (!timer) {
    __showLoading({ useSystemLoading, title, icon, mask, duration, maskTime })
  }
  else {
    resetTime()
  }
}
function delayTime(time: number): Promise<boolean> {
  return new Promise(resolve => {
    timer = setTimeout(() => {
      resolve(true)
    }, time)
  })
}
let timerPromise: Promise<boolean> | null = null
async function hideLoading(useSystemLoading: boolean) {
  reqTimes -= 1
  if (reqTimes <= 0) {
    timerPromise = delayTime(300)
    await timerPromise
    __hideLoading(useSystemLoading)
  }
}

async function busiToast(msg: string) {
  await timerPromise
  toast(msg)
}

function errorCode(response: HttpResponse<any, HttpTask> | HttpError<any, HttpTask>, msgKey: string) {
  switch (response.statusCode) {
    case 200:
      busiToast(response.data[msgKey] || JSON.stringify(response.data)) // 服务器返回200但是业务数据状态为false提示
      break
    case 404:
      busiToast('服务器资源丢失啦~')
      break
    case 401:
      busiToast('暂未登录~')
      break
    case 500:
      busiToast('系统维护中，请稍后重试~')
      break
    default:
      if (response?.errMsg?.includes('timeout') || response?.errMsg?.includes('fail')) {
        busiToast('网络请求超时~')
        return
      }
      if (response?.data?.[msgKey]) {
        busiToast(response.data[msgKey])
        return
      }
      busiToast(`o(╥﹏╥)o:未知错误:${response.errMsg}`)
      break
  }
}
/**
 * @type {LoadingConfig}
 */
export function loadingPlugin({ useSystemLoading = true, duration = 10000, maskTime = 100, title = '正在加载中...', icon, mask = true, showTip = true, showBusiTip, msgKey = 'msg' }: LoadingConfig) {
  return {
    name: 'loadingPlugin',
    onRequestSuccess: (config: HttpRequestConfig<HttpTask>) => {
      const isShowLoading = config?.custom?.showLoading
      if (isShowLoading === undefined || isShowLoading) {
        if (reqTimes === 0) {
          showLoading({ useSystemLoading, maskTime, duration, title, icon, mask })
        }
        reqTimes += 1
      }
      return config
    },
    onResponseSuccess: (response: HttpResponse<any, HttpTask>) => {
      const isShowLoading = response?.config?.custom?.showLoading
      if (isShowLoading === undefined || isShowLoading) {
        hideLoading(useSystemLoading)
      }
      // 错误码弹窗处理
      const statusCode = response.statusCode
      const hasShowBusiTip = response.config.custom?.showBusiTip
      // 是否显示业务码错误提示
      showBusiTip && (hasShowBusiTip === undefined || hasShowBusiTip) && statusCode === 200 && errorCode(response, msgKey)
      return response
    },
    onResponseFail: (err: HttpError<any, HttpTask>) => {
      const isShowLoading = err.config?.custom?.showLoading
      if (isShowLoading === undefined || isShowLoading) {
        hideLoading(useSystemLoading)
      }

      // 是否显示错误提示
      const hasShowTip = err.config?.custom?.showTip
      showTip && (hasShowTip === undefined || hasShowTip) && errorCode(err, msgKey)
      return Promise.reject(err)
    }
  }
}
